home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 365_01 / cmd1.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  36KB  |  1,775 lines

  1. /* cmd1.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains some of the EX commands - mostly ones that deal with
  12.  * files, options, etc. -- anything except text.
  13.  */
  14.  
  15. #include "config.h"
  16. #include "ctype.h"
  17. #include "vi.h"
  18. #include "regexp.h"
  19.  
  20. #ifdef DEBUG
  21. /* print the selected lines with info on the blocks */
  22. /*ARGSUSED*/
  23. void cmd_debug(frommark, tomark, cmd, bang, extra)
  24.     MARK    frommark;
  25.     MARK    tomark;
  26.     CMD    cmd;
  27.     int    bang;
  28.     char    *extra;
  29. {
  30.     REG char    *scan;
  31.     REG long    l;
  32.     REG int        i;
  33.     int        len;
  34.  
  35.     /* scan lnum[] to determine which block its in */
  36.     l = markline(frommark);
  37.     for (i = 1; l > lnum[i]; i++)
  38.     {
  39.     }
  40.  
  41.     do
  42.     {
  43.         /* fetch text of the block containing that line */
  44.         scan = blkget(i)->c;
  45.  
  46.         /* calculate its length */
  47.         if (scan[BLKSIZE - 1])
  48.         {
  49.             len = BLKSIZE;
  50.         }
  51.         else
  52.         {
  53.             len = strlen(scan);
  54.         }
  55.  
  56.         /* print block stats */
  57.         msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)",
  58.             i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]);
  59.         msg("##### len=%d, buf=0x%lx, %sdirty",
  60.             len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not ");
  61.         if (bang)
  62.         {
  63.             while (--len >= 0)
  64.             {
  65.                 addch(*scan);
  66.                 scan++;
  67.             }
  68.         }
  69.         exrefresh();
  70.  
  71.         /* next block */
  72.         i++;
  73.     } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));
  74. }
  75.  
  76.  
  77. /* This function checks a lot of conditions to make sure they aren't screwy */
  78. /*ARGSUSED*/
  79. void cmd_validate(frommark, tomark, cmd, bang, extra)
  80.     MARK    frommark;
  81.     MARK    tomark;
  82.     CMD    cmd;
  83.     int    bang;
  84.     char    *extra;
  85. {
  86.     char    *scan;
  87.     int    i;
  88.     int    nlcnt;    /* used to count newlines */
  89.     int    len;    /* counts non-NUL characters */
  90.  
  91.     /* check lnum[0] */
  92.     if (lnum[0] != 0L)
  93.     {
  94.         msg("lnum[0] = %ld", lnum[0]);
  95.     }
  96.  
  97.     /* check each block */
  98.     for (i = 1; lnum[i] <= nlines; i++)
  99.     {
  100.         scan = blkget(i)->c;
  101.         if (scan[BLKSIZE - 1])
  102.         {
  103.             msg("block %d has no NUL at the end", i);
  104.         }
  105.         else
  106.         {
  107.             for (nlcnt = len = 0; *scan; scan++, len++)
  108.             {
  109.                 if (*scan == '\n')
  110.                 {
  111.                     nlcnt++;
  112.                 }
  113.             }
  114.             if (scan[-1] != '\n')
  115.             {
  116.                 msg("block %d doesn't end with '\\n' (length %d)", i, len);
  117.             }
  118.             if (bang || nlcnt != lnum[i] - lnum[i - 1])
  119.             {
  120.                 msg("block %d (line %ld?) has %d lines, but should have %ld",
  121.                     i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]);
  122.             }
  123.         }
  124.         exrefresh();
  125.     }
  126.  
  127.     /* check lnum again */
  128.     if (lnum[i] != INFINITY)
  129.     {
  130.         msg("hdr.n[%d] = %d, but lnum[%d] = %ld",
  131.             i, hdr.n[i], i, lnum[i]);
  132.     }
  133.  
  134.     msg("# = \"%s\", %% = \"%s\"", prevorig, origname);
  135.     msg("V_from=%ld.%d, cursor=%ld.%d", markline(V_from), markidx(V_from), markline(cursor), markidx(cursor));
  136. }
  137. #endif /* DEBUG */
  138.  
  139.  
  140. /*ARGSUSED*/
  141. void cmd_mark(frommark, tomark, cmd, bang, extra)
  142.     MARK    frommark;
  143.     MARK    tomark;
  144.     CMD    cmd;
  145.     int    bang;
  146.     char    *extra;
  147. {
  148.     /* validate the name of the mark */
  149.     if (*extra == '"')
  150.     {
  151.         extra++;
  152.     }
  153.     /* valid mark names are lowercase ascii characters */
  154.     if (!isascii(*extra) || !islower(*extra) || extra[1])
  155.     {
  156.         msg("Invalid mark name");
  157.         return;
  158.     }
  159.  
  160.     mark[*extra - 'a'] = tomark;
  161. }
  162.  
  163. /*ARGSUSED*/
  164. void cmd_write(frommark, tomark, cmd, bang, extra)
  165.     MARK    frommark;
  166.     MARK    tomark;
  167.     CMD    cmd;
  168.     int    bang;
  169.     char    *extra;
  170. {
  171.     int        fd;
  172.     int        append;    /* boolean: write in "append" mode? */
  173.     REG long    l;
  174.     REG char    *scan;
  175.     REG int        i;
  176.  
  177.     /* if writing to a filter, then let filter() handle it */
  178.     if (*extra == '!')
  179.     {
  180.         filter(frommark, tomark, extra + 1, FALSE);
  181.         return;
  182.     }
  183.  
  184.     /* if all lines are to be written, use tmpsave() */
  185.     if (frommark == MARK_FIRST && tomark == MARK_LAST && cmd == CMD_WRITE)
  186.     {
  187.         tmpsave(extra, bang);
  188.         return;
  189.     }
  190.  
  191.     /* see if we're going to do this in append mode or not */
  192.     append = FALSE;
  193.     if (extra[0] == '>' && extra[1] == '>')
  194.     {
  195.         extra += 2;
  196.         append = TRUE;
  197.     }
  198.  
  199.     /* either the file must not exist, or we must have a ! or be appending */
  200.     if (access(extra, 0) == 0 && !bang && !append)
  201.     {
  202.         msg("File already exists - Use :w! to overwrite");
  203.         return;
  204.     }
  205.  
  206.     /* else do it line-by-line, like cmd_print() */
  207.     if (append)
  208.     {
  209. #ifdef O_APPEND
  210.         fd = open(extra, O_WRONLY|O_APPEND);
  211. #else
  212.         fd = open(extra, O_WRONLY);
  213.         if (fd >= 0)
  214.         {
  215.             lseek(fd, 0L, 2);
  216.         }
  217. #endif
  218.     }
  219.     else
  220.     {
  221.         fd = -1; /* so we know the file isn't open yet */
  222.     }
  223.  
  224.     if (fd < 0)
  225.     {
  226.         fd = creat(extra, FILEPERMS);
  227.         if (fd < 0)
  228.         {
  229.             msg("Can't write to \"%s\"", extra);
  230.             return;
  231.         }
  232.     }
  233.     for (l = markline(frommark); l <= markline(tomark); l++)
  234.     {
  235.         /* get the next line */
  236.         scan = fetchline(l);
  237.         i = strlen(scan);
  238.         scan[i++] = '\n';
  239.  
  240.         /* print the line */
  241.         if (twrite(fd, scan, i) < i)
  242.         {
  243.             msg("Write failed");
  244.             break;
  245.         }
  246.     }
  247.     rptlines = markline(tomark) - markline(frommark) + 1;
  248.     rptlabel = "written";
  249.     close(fd);
  250. }    
  251.  
  252.  
  253. /*ARGSUSED*/
  254. void cmd_shell(frommark, tomark, cmd, bang, extra)
  255.     MARK    frommark, tomark;
  256.     CMD    cmd;
  257.     int    bang;
  258.     char    *extra;
  259. {
  260.     static char    prevextra[80];
  261.  
  262.     /* special case: ":sh" means ":!sh" */
  263.     if (cmd == CMD_SHELL)
  264.     {
  265.         extra = o_shell;
  266.         frommark = tomark = 0L;
  267.     }
  268.  
  269.     /* if extra is "!", substitute previous command */
  270.     if (*extra == '!')
  271.     {
  272.         if (!*prevextra)
  273.         {
  274.             msg("No previous shell command to substitute for '!'");
  275.             return;
  276.         }
  277.         extra = prevextra;
  278.     }
  279.     else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1)
  280.     {
  281.         strcpy(prevextra, extra);
  282.     }
  283.  
  284.     /* warn the user if the file hasn't been saved yet */
  285.     if (*o_warn && tstflag(file, MODIFIED))
  286.     {
  287.         if (mode == MODE_VI)
  288.         {
  289.             mode = MODE_COLON;
  290.         }
  291.         msg("Warning: \"%s\" has been modified but not yet saved", origname);
  292.     }
  293.  
  294.     /* if no lines were specified, just run the command */
  295.     suspend_curses();
  296.     if (frommark == 0L)
  297.     {
  298.         system(extra);
  299.     }
  300.     else /* pipe lines from the file through the command */
  301.     {
  302.         filter(frommark, tomark, extra, TRUE);
  303.     }
  304.  
  305.     /* resume curses quietly for MODE_EX, but noisily otherwise */
  306.     resume_curses(mode == MODE_EX);
  307. }
  308.  
  309.  
  310. /*ARGSUSED*/
  311. void cmd_global(frommark, tomark, cmd, bang, extra)
  312.     MARK    frommark, tomark;
  313.     CMD    cmd;
  314.     int    bang;
  315.     char    *extra;    /* rest of the command line */
  316. {
  317.     char    *cmdptr;    /* the command from the command line */
  318.     char    cmdln[100];    /* copy of the command from the command line */
  319.     char    *line;        /* a line from the file */
  320.     long    l;        /* used as a counter to move through lines */
  321.     long    lqty;        /* quantity of lines to be scanned */
  322.     long    nchanged;    /* number of lines changed */
  323.     regexp    *re;        /* the compiled search expression */
  324.  
  325.     /* can't nest global commands */
  326.     if (doingglobal)
  327.     {
  328.         msg("Can't nest global commands.");
  329.         rptlines = -1L;
  330.         return;
  331.     }
  332.  
  333.     /* ":g! ..." is the same as ":v ..." */
  334.     if (bang)
  335.     {
  336.         cmd = CMD_VGLOBAL;
  337.     }
  338.  
  339.     /* make sure we got a search pattern */
  340.     if (*extra != '/' && *extra != '?')
  341.     {
  342.         msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v');
  343.         return;
  344.     }
  345.  
  346.     /* parse & compile the search pattern */
  347.     cmdptr = parseptrn(extra);
  348.     if (!extra[1])
  349.     {
  350.         msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
  351.         return;
  352.     }
  353.     re = regcomp(extra + 1);
  354.     if (!re)
  355.     {
  356.         /* regcomp found & described an error */
  357.         return;
  358.     }
  359.  
  360.     /* for each line in the range */
  361.     doingglobal = TRUE;
  362.     ChangeText
  363.     {
  364.         /* NOTE: we have to go through the lines in a forward order,
  365.          * otherwise "g/re/p" would look funny.  *BUT* for "g/re/d"
  366.          * to work, simply adding 1 to the line# on each loop won't
  367.          * work.  The solution: count lines relative to the end of
  368.          * the file.  Think about it.
  369.          */
  370.         for (l = nlines - markline(frommark),
  371.             lqty = markline(tomark) - markline(frommark) + 1L,
  372.             nchanged = 0L;
  373.              lqty > 0 && nlines - l >= 0 && nchanged >= 0L;
  374.              l--, lqty--)
  375.         {
  376.             /* fetch the line */
  377.             line = fetchline(nlines - l);
  378.  
  379.             /* if it contains the search pattern... */
  380.             if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL))
  381.             {
  382.                 /* move the cursor to that line */
  383.                 cursor = MARK_AT_LINE(nlines - l);
  384.  
  385.                 /* do the ex com